/*
*    Qizx/open 3.0 beta
*
* This code is the open-source version of Qizx.
* Copyright (C) 2004-2009 Axyana Software -- All rights reserved.
*
* The contents of this file are subject to the Mozilla Public License 
*  Version 1.1 (the "License"); you may not use this file except in 
*  compliance with the License. You may obtain a copy of the License at
*  http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
*  for the specific language governing rights and limitations under the
*  License.
*
* The Initial Developer of the Original Code is Xavier Franc - Axyana Software.
*
*/
using System;
using EvaluationException = System.Qizx.Api.EvaluationException;
using System.Qizx.XQuery;
using IntegerValue = System.Qizx.XQuery.Dt.IntegerValue;
using SingleInteger = System.Qizx.XQuery.Dt.SingleInteger;
using EmptyException = System.Qizx.XQuery.Impl.EmptyException;
namespace System.Qizx.XQuery.Op
{
	
	/// <summary> integer range x to y.</summary>
	public class RangeExpr:Expression
	{
		public Expression lower;
		public Expression upper;
		
		public RangeExpr(Expression expr1, Expression expr2)
		{
			this.lower = expr1;
			this.upper = expr2;
		}
		
		public override Expression Child(int rank)
		{
			return (rank == 0)?lower:((rank == 1)?upper:null);
		}
		
		public override void  Dump(ExprDisplay d)
		{
			d.header(this);
			d.child("lower", lower);
			d.child("upper", upper);
		}
		
		public override Expression StaticCheck(ModuleContext context, int flags)
		{
			lower = context.staticCheck(lower, 0);
			upper = context.staticCheck(upper, 0);
			type = XQType.INTEGER.star;
			// type = context.check(proto, new Expression[] { expr1, expr2 });
			return this;
		}
		
		public override XQValue eval(Focus focus, EvalContext context)
		{
			context.at(this);
			try
			{
				return new Sequence(lower.evalAsOptInteger(focus, context), upper.evalAsOptInteger(focus, context));
			}
			catch (EmptyException e)
			{
				return System.Qizx.XQuery.XQValues.Empty;
			}
		}
		
		/// <summary> Evaluate as a pair of int, not as a sequence</summary>
		public virtual int[] evaluate(Focus focus, EvalContext context)
		{
			long lo = (lower == null)?0:lower.evalAsInteger(focus, context);
			// for 'exactly' range in FT, the two expressions are identical:
			long up = (upper == lower)?lo:((upper == null)?System.Int64.MaxValue:upper.evalAsInteger(focus, context));
			return new int[]{(int) lo, (int) up};
		}
		
		internal class Sequence:IntegerValue
		{
			public override long ValueAsInteger
			{
				get
				{
					return current;
				}
				
			}
			internal long start, end;
			
			internal long current;
			
			internal Sequence(long start, long end)
			{
				// System.out.println(" range "+start+" : "+end);
				this.start = start;
				this.end = end;
				if (start <= end)
					current = start - 1;
				else
					current = start + 1;
			}
			
			public override bool Next()
			{
				// NOV 2003
				// if(start <= end)
				return (++current <= end);
				// else return (-- current >= end);
			}
			
			public override long QuickCount(EvalContext context)
			{
				return System.Math.Max(0, end - start + 1);
			}
			
			public override bool HasQuickIndex()
			{
				return true;
			}
			
			public override XQItem QuickIndex(long index)
			{
				if (index < 1 || index > end - start + 1)
					return null;
				return new SingleInteger(current = start + index - 1);
			}
			
			public override XQValue BornAgain()
			{
				return new Sequence(start, end);
			}
			
			public override bool WorthExpanding()
			{
				return false;
			}
			
			public override long getValue()
			{
				return current;
			}
		}
	}
}